#ifndef _SOCKET_
#define _SOCKET_

#include <arpa/inet.h>
#include <sys/time.h>
#include "signal.h"

#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>

#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>

#include <pthread.h>
#include <iostream>
using namespace std;

#include "../Packets/jsmsg.h"

#define SIZE 512*1024

//extern int g_nMaxConnectNum ;   //最大连接数
//extern int g_nCurConnectNum ;   //当前连接数

//没用到的数据结构
typedef struct
{
	int nType;
	int nLen;
	BYTE *pBuffer;
}Package;

//返回server fd
int JS_TCPServer(int nPort, int nMaxConnectNum);

//返回client fd
int JS_TCPClient(char *pIPAddr, int nPort);

int JS_UDPServer(int nPort);
int JS_UDPClient();

//============================================
//参数：eventID 没有用到
//参数：param   返回Accept到的IP，如果拒绝连接，则为NULL
//返回：0成功，－1失败
//说明：accpt一个网络连接，并根据最大连接数，看是否Accept。
//============================================
int JS_OnAccept(int nFd, int eventID, void *param);
/*
int JS_OnRecv(int nFd, int eventID, void *param);
int JS_OnSend(int nFd, int eventID, void *param);

int JS_Net(int nfd,int event,void *);
int JS_OnConnect(int nfd,int event,void *);
*/

//=============================================
//函数说明：读取指定长度nLen，数据存储到pBuf中，返回实际的读取长度。
//也说是是说，读到实际的长度<=nLen。每次读到0长度为0或－1则为出错了 。
//=============================================
int RecvData(int nFd, char *pBuf, int nLen);

//==============================================
//函数说明：读取指定长度len，数据存储到pBuf中，返回实际的读取长度，
//如果读到不指定长度，则阻塞等待。每次读到0长度为0或－1则为出错了 。并清空pBuf
//也就是必须接收nLen长度的数据
//==============================================
int RecvDataN(int nFd, char *pBuf, int nLen);

//ReadPackage(int nFd, char *pBuf);

//==============================================
//函数说明：发送pBuf中的数据，长度为nLen，实际发送长度<=nLen
//==============================================
int SendData(int nFd, char *pBuf, int nLen);

//==============================================
//函数说明：发送pBuf中的数据，长度为nLen，实际发送长度=nLen
//也就是必须发送nLen长度的数据
//==============================================
int SendDataN(int nFd, char *pBuf, int nLen);

//==============================================
//函数说明：发送一个msg包的数据，一次必须发送完
//==============================================
int SendMsg(int nFd, CJSMsg &msg);

//==============================================
//函数说明：接收一个msg包的数据（TLV的结构），一次接收的必须是一个完整的数据包
//实现方法：先接收8个字节的TL，解包出L，根据L的长度，RecvDataN。
//==============================================
int RecvMsg(int nFd, CJSMsg &msg);


//==============================================
//函数说明：用于UDP发送，一次发送一个msg（TLV包）
//返回值：发送的实际长度
//==============================================
int SendMsgTo(int nFd, CJSMsg &msg, struct sockaddr_in *to);
//==============================================
//函数说明：用于UDP接收，一次最多接收512*1024个字节，并封装成TLV包
//参数说明：from可以为NULL，表示不关心来源的IP和Port
//返回值：接收的实际长度
//==============================================
int RecvMsgFrom(int nFd, CJSMsg &msg, struct sockaddr_in *from);


//==============================================
//函数说明：用于UDP接收，to里面有发送的IP和Port
//返回值：发送的实际长度
//==============================================
int SendTo(int sockfd, char *pBuf, int len, struct sockaddr_in *to);

//==============================================
//函数说明：用于UDP接收
//from可以为NULL，表示不关心来源的IP和Port
//返回值：接收的实际长度
//==============================================
int RecvFrom(int sockfd, char *pBuf, int len, struct sockaddr_in *from);

//后端发送一个数据包，可用在对configSocket和resultSocket的发送
//一次必须发送一个完整的数据包，否则不返回
//返回值：成功返回发送长度，失败-1
int SendMsg_Net(int nFd, char *pBuf, int nLen);

//接收configSocket连接发送过来的包，一次返回一个包，放入到pBuf中。
//函数内部维护一个static buf。
//如果一次接收的包的数据大于1，则下次可接收时，直接取，不接收网络上的数据
//返回值：成功 包的长度，失败-1
//注：还有bug
int RecvMsg_ConfigNet(int nFd, char *pBuf);
int RecvMsg_ResultNet(int nFd, char *pBuf);

//没有用的函数
int PackNum(char *buffer, int length);

//没有用的函数
int EndSocket(int nFd);

//===========================================
//参数说明：msg 为传入参数（TLV包），data为返回的包（configSocket发送的包，加好包头）
//函数说明：将TLV包转换成在configSocket上发送的包
//返回值：转换之后包的长度
//data指向的数据由上层释放
//将TLV转换成以下数据包格式。注TLV中的V值为：len(4字节) data(=以下的value)
//数据包格式：
//0xaa55aa55	length		value
//4				4			length
//返回config socket发送包的长度 = 4 + 4 + length
//===========================================
int TLVtoConfigNetPackage(CJSMsg &msg, BYTE** data);

//============================================
//将TLV包转换成以下数据包格式.注：TLV包中的V值为:len(4字节) data(从类型到校验码)
//数据包格式:
//0x55aa	类型		长度(length)		Value		校验码	0xaa55
//2			1		2				length		1		2
//返回值= 2 + 1 + 2 + length + 1 + 2
//============================================
int TLVtoResultNetPackage(CJSMsg &msg, BYTE** data);


//实现socket API为包裹函数
int Socket(int family, int type, int protocol);
int Bind(int sockfd, struct sockaddr *addr, int addrlen);
int Listen(int sockfd, int maxConnectNum);
int Connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
int Accept(int servfd, struct sockaddr *addr, socklen_t *addrlen);
int Send(int sockfd, char *pBuf, int len);
int Recv(int sockfd, char *pBuf, int len);
int Sendto(int sockfd, char *pBuf, int len, int flag, struct sockaddr *to, int tolen);
int Recvfrom(int sockfd, char *pBuf, int len, int flag, struct sockaddr *from, socklen_t *fromlen);
int Close(int sockfd);


#endif

